#ifndef ODN_GAMEMGR_H
#define ODN_GAMEMGR_H

#include <opal\opal.h>
#include <ogre\Ogre.h>
#include <ogre\OgreKeyEvent.h>
#include <ogre\OgreEventListeners.h>

#include "ODN_Networking.h"
//#include "ODN_GameState.h"
#include "ODN_GameTimer.h"
#include "ODN_InputDevice.h"
#include "ODN_Singleton.h"
#include "ODN_Containers.h"
#include "ODN_GameWorld.h"
#include "ODN_Maths.h"
#include "ODN_ModelEntity.h"
#include "ODN_ModelBit.h"

//TODO: Check if this is needed
//#define MODEL_PATH "models\\"

//TODO: Look into network interface creation and pointers and think about server
// acting as client and hence only ever one network interface

namespace ouden {

class CGameState;

//This class basically manages the game states and directs basic frame and input
// events to the current game state
class CGameMgr : public Ogre::FrameListener, public Ogre::KeyListener, public CSingleton<CGameMgr>
{
	public:
		CGameMgr();
		virtual ~CGameMgr();

		//Main function to begin the game
		void start(CGameState* pGameState);


		//static CGameMgr* getInstance() 		{ return m_pInstance; }


		//Game state management functions
		void changeState(CGameState* state);
		void pushState(CGameState* state);
		void popState();

		//Game management object access functions
		Ogre::Root* 		getOgreRoot() 			{ return m_pRoot; }
		Ogre::RenderWindow* getOgreWindow() 		{ return m_pWindow; }
		IInputDevice* 		getInputDevice() 		{ return m_pInputDevice; }
		Ogre::SceneManager* getSceneMgr()			{ return m_pSceneMgr; }
		Ogre::Camera* 		getMainCamera() 		{ return m_pCamera; }
		CGameWorld* 		getGameWorld() 			{ return m_pGameWorld; }
		opal::Simulator* 	getSimulator() 			{ return m_pSimulator; }
		CGameTimer*         getGameTimer()          { return m_pGameTimer; }

		void beginServerConnection(MultiplayerServer* pPacketHandler, unsigned short iMaxPlayers, unsigned short iServerPort)
		{
			m_pServer = new CServerInterface(pPacketHandler, iMaxPlayers, iServerPort);
			m_bIsServer = true;
		}

		void beginClientConnection(MultiplayerClient* pPacketHandler, String sHostAddress, unsigned short iServerPort, unsigned short iClientPort)
		{
			m_pClient = new CClientInterface(pPacketHandler, sHostAddress, iServerPort, iClientPort);
			m_bIsClient = true;
		}

	protected:

		//Game events
		//TODO: Do these need to be virtual?
		//TODO: Maybe wrap these two functions to be onFrameStart and also think about onTick

		//Ogre FrameListener events call onTick, frameStarted and frameEnded in current game state
		virtual bool frameStarted(const Ogre::FrameEvent &evt);
		virtual bool frameEnded(const Ogre::FrameEvent &evt);

		//Ogre KeyListener events redirect to onKeyDown and onKeyUp events in the current game state class
		virtual void 	keyClicked (Ogre::KeyEvent *e);
		virtual void 	keyPressed (Ogre::KeyEvent *e);
		virtual void 	keyReleased (Ogre::KeyEvent *e);

		//Override this to create and initialise all scene elements
		//virtual void createScene() = 0;

		//Override this to destroy and clean up all the scene elements
		//virtual void destroyScene() = 0;


		//Game management objects
		Ogre::Root*				m_pRoot; 			//Root Ogre object provides access to Ogre engine
		Ogre::RenderWindow* 	m_pWindow;			//Main renderer window
		Ogre::EventProcessor* 	m_pEventProcessor; 	//Ogre event processor for setting up input
		Ogre::SceneManager* 	m_pSceneMgr;		//Ogre Scene manager object
		Ogre::Viewport* 		m_pViewport;
		Ogre::Camera* 			m_pCamera;			//Main game camera

		IInputDevice* 			m_pInputDevice; 	//Unbuffered input reader
		CGameTimer* 			m_pGameTimer; 		//Main game timer which calls tick and frame events
		CGameWorld* 			m_pGameWorld;		//Game world object which holds all game entities

		//TODO: What is this for? Ogre::Timer* 			m_pTimer;
		opal::Simulator* 		m_pSimulator;		//Physics simulator

		//TODO: Remove these
		//RakClientInterface* 	m_pNetworkClient; 	//Network client instance
		//RakServerInterface* 	m_pNetworkServer; 	//Network server instance
		//INetworkMgr* 			m_pNetworkMgr;

		//Network objects
		CClientInterface* 		m_pClient; 			//Network client handler instance
		CServerInterface* 		m_pServer; 			//Network server handler instance

		//Game management flags
		bool 					m_bIsServer; 		//Is the game acting as a server
		bool 					m_bIsClient; 		//Is the game acting as a client
		bool m_bFinished; 		//If true then exits main loop on next frame



	private:

		//Main engine initialisation function called by run()
		bool init();

		//Main engine cleanup function called after the main loop is finished
		bool cleanup();

		//Loads all game resources as specified in the resources.cfg file
		bool loadResources();

		//Stack of current game states
		Array<CGameState*> m_pGameStates;

};

} //namespace ouden

#endif // ODN_GAMEMGR_H
